package pt.compflow.activity.gateway;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import pt.compflow.flowontology.model.FLOWO;
import pt.compflow.flowontology.model.FlowOntologyModel;
import pt.compflow.flowontology.model.Gateway;
import pt.compflow.tools.OntModelHelper;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;

public class AskEvaluationFilter {

	private static final Logger LOG = LoggerFactory.getLogger(AskEvaluationFilter.class);
	
	// FIXME change these prefixes to a config file? use prefixes found in the workflow-definition ontology?
	protected static final String PREFIXES = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n "
			+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n " + "PREFIX dc: <http://purl.org/dc/terms/>\n "
			+ "PREFIX cflow: <" + FLOWO.getURI() + ">\n ";

	protected OntModelHelper ontModelHelper;
	protected FlowOntologyModel jobModel;
	protected Gateway gateway;

	protected List<String> nextActivityDefinitionUris;

	public AskEvaluationFilter(OntModelHelper ontModelHelper, FlowOntologyModel jobModel, Gateway gateway) {
		this.ontModelHelper = ontModelHelper;
		this.jobModel = jobModel;
		this.gateway = gateway;
	}

	protected void parseRule(JSONObject rule) {
		String ask = rule.getString("ask").replace("?WORKFLOW", "<" + gateway.getActivityOfWorkflow().getURI() + ">");
		String queryString = "PREFIX : <" + gateway.getNameSpace() + ">\n " + PREFIXES + "ASK { ?PREVTASK cflow:transitionTo <" + gateway.getURI() + "> . " + ask + " }";
		LOG.debug("Asking: " + "ASK { ?PREVTASK cflow:transitionTo <" + gateway.getURI() + "> . " + ask + " }");
		
		Query query = QueryFactory.create(queryString);
		QueryExecution qexec = QueryExecutionFactory.create(query, jobModel);
	    boolean result = qexec.execAsk();
	    LOG.debug("Ask Result: " + result);
	    qexec.close() ;
	    
	    Object obj = rule.opt("true");
	    if(!result) obj = rule.opt("false");
	    	
	    if(obj != null) {
	    	if(obj instanceof JSONObject) {
	    		parseRule((JSONObject) obj);
	    	} else {
	    		String[] nextActivityDefUris = obj.toString().split(",");
	    		for(String activityDefUri : nextActivityDefUris)
	    			nextActivityDefinitionUris.add(activityDefUri.trim());
	    	}
	    }
	}

	public List<String> getNextActivities() {
		
		Resource gatewayClass = ontModelHelper.getDirectLeafType(gateway, FLOWO.DecisionOutputGateway.getURI());
		Statement stmt = ontModelHelper.getOntModel().getProperty(gatewayClass, FLOWO.decisionRule);
		if (stmt == null) {
			throw new RuntimeException("Gateway " + gatewayClass.getURI() + " doesn't have a decision rule.");
		}

		if(nextActivityDefinitionUris != null) nextActivityDefinitionUris.clear();
		else nextActivityDefinitionUris = new ArrayList<String>();

		Literal ruleLiteral = stmt.getObject().asLiteral();
		String ruleString = ruleLiteral.getString();

		JSONArray rules = new JSONArray(ruleString);
		for (int i = 0; i < rules.length(); i++) {
			parseRule(rules.getJSONObject(i));
		}
				
		return nextActivityDefinitionUris;
	}

}
